<?php

namespace LhpAmis\Traits;

use think\exception\HttpResponseException;
use think\facade\Db;
use think\Response;
use Throwable;
use LhpAmis\Renderers\Amis;

/**
 * Trait JumpTrait
 * @package app\common\traits
 */
trait JumpTrait
{  
 
    /**
     * 返回数据
     * @access protected
     * @param mixed $data 返回的数据
     * @param mixed $msg 提示信息
     * @param array $header 发送的 Header 信息
     * @return Response
     */
    protected function data($data = [], $msg = '操作成功', array $header = [])
    {

        return $this->result($data, 0, $msg, $header);
    }
    /**
     * 操作成功跳转的快捷方法
     * @access protected
     * @param mixed $msg 提示信息
     * @param mixed $data 返回的数据
     * @param array $header 发送的 Header 信息
     * @return Response
     */
    protected function success($msg = '操作成功', $data = [], array $header = [])
    {

        return $this->result($data, 0, $msg, $header);
    }

    /**
     * 获取出错文件内容
     * 获取错误的前9行和后9行
     * @access protected
     * @param Throwable $exception
     * @return array                 错误文件内容
     */
    protected function getSourceCode(Throwable $exception): array
    {
        // 读取前9行和后9行
        $line  = $exception->getLine();
        $first = ($line - 9 > 0) ? $line - 9 : 1;

        try {
            $contents = file($exception->getFile()) ?: [];
            $source   = [
                'first' => $first,
                'source' => array_slice($contents, $first - 1, 19),
            ];
        }
        catch (\Exception $e) {
            $source = [];
        }

        return $source;
    }

    /**
     * 操作错误跳转的快捷方法
     * @access protected
     * @param mixed $th 返回的数据
     * @param mixed $msg 提示信息
     * @param string $url 跳转的 URL 地址
     * @param array $header 发送的 Header 信息
     * @return Response
     */
    protected function Throwable(Throwable $th, array $header = [])
    {
        $data = [
            'name' => get_class($th),
            'file' => $th->getFile(),
            'line' => $th->getLine(),
            'code' => $th->getCode(),
            'message' => $th->getMessage(),
            'trace' => $th->getTrace(),
            'source' => $this->getSourceCode($th),
            'lastSql' => Db::getLastSql(),
        ];
        return $this->result($data, 1, $th->getMessage(), $header);
    }

    /**
     * 操作错误跳转的快捷方法
     * @access protected
     * @param mixed $data 返回的数据
     * @param mixed $msg 提示信息
     * @param string $url 跳转的 URL 地址
     * @param array $header 发送的 Header 信息
     * @return Response
     */
    protected function error($msg = '操作失败', $data = [], array $header = [])
    {
        return $this->result($data, 1, $msg, $header);
    }

    /**
     * 返回封装后的 API 数据到客户端
     * @access protected
     * @param mixed $data 要返回的数据
     * @param int $code 返回的 code
     * @param mixed $msg 提示信息
     * @param array $header 发送的 Header 信息
     * @return Response
     */
    protected function result($data, $code = 0, $msg = '', array $header = [])
    {
        $result = [
            'status' => $code,
            'code' => $code,
            'msg' => $msg,
            'time' => time(),
            'data' => $data,
        ];
        $type   = $this->getResponseType();
        if ($type == 'html') {
            $page         = Amis::make()->Page()->title('错误页面')->className('m:overflow-auto pb-48')->body($this->tpl($code, $msg, $data));
            $this->layout = dirname(__DIR__).DIRECTORY_SEPARATOR.'view'.DIRECTORY_SEPARATOR.'index.html';

            return $this->app->view->fetch($this->layout, ['amisJSON' => $page]);
        }
        return Response::create($result, $type)->header($header)->code(200)->options([
            'json_encode_param' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
        ]);
    }

    private function tpl($code, $message, $data): array
    {
        return [
            "type" => "page",
            "body" => [
                [
                    "type" => "tpl",
                    "tpl" => "<p>错误代码: {$code}</p><p>错误信息: {$message}</p>"
                ],
                [
                    "type" => "list",
                    "source" => $data,
                    "listItem" => [
                        //                        "type" => "wrapper",
//                        "header" => [
//                            "title" => "{$code} - {$message}"
//                        ],
                        "body" => [
                            [
                                "type" => "tpl",
                                "tpl" => '<p>错误代码: ${code}</p><p>错误信息: ${message}</p>'
                            ],
                            //                            "1" => [
//                                "type" => "button",
//                                "label" => "返回首页",
//                                "actionType" => "link",
//                                "link" => "#/"
//                            ]
                        ]
                    ]
                ]
            ]
        ];
    }

    /**
     * URL 重定向
     * @access protected
     * @param string $url 跳转的 URL 表达式
     * @param int $code http code
     * @param array $with 隐式传参
     * @return void
     * @throws HttpResponseException
     */
    protected function redirect($url = [], $code = 302, $header = [])
    {
        $result = [
            'status' => $code,
            'code' => $code,
            'msg' => '',
            'time' => time(),
            'data' => [],
        ];
        $type   = $this->getResponseType();
        if ($type == 'html') {
            $response = Response::create($url, 'redirect', $code);
            throw new HttpResponseException($response);
        } else {
            return Response::create($result, $type)->header($header)->code(200)->options([
                'json_encode_param' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
            ]);
        }
    }

    /**
     * 获取当前的 response 输出类型
     * @access protected
     * @return string
     */
    protected function getResponseType(): string
    {
        return (request()->isJson() || request()->isAjax() || request()->isPost()) ? 'json' : 'html';
    }
}
